﻿namespace Paw.Services.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.Web.Mvc;
    using System.Web.Security;
    using Paw.Services.Infrastructure;
    using Paw.Services.MembershipWrappers;
    using Paw.Services.Models;
    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.StorageClient;

    public class AdminController : Controller
    {
        public AdminController()
            : this(null, new RoleProviderWrapper(), new AccountMembershipService())
        {
        }

        public AdminController(CloudTableClient cloudTableClient, RoleProvider roleProvider, IMembershipService membershipService)
        {
            if ((cloudTableClient == null) && (GetStorageAccountFromConfigurationSetting() == null))
            {
                throw new ArgumentNullException("cloudTableClient", "Cloud Table Client cannot be null if no configuration is loaded.");
            }

            this.CloudTableClient = cloudTableClient ?? GetStorageAccountFromConfigurationSetting().CreateCloudTableClient();
            this.RoleProvider = roleProvider;
            this.MembershipService = membershipService;
        }

        public CloudTableClient CloudTableClient { get; private set; }

        public RoleProvider RoleProvider { get; private set; }

        public IMembershipService MembershipService { get; private set; }

        [CustomAuthorize(Roles = RoleConstants.AdminRole)]
        public ActionResult Index()
        {
            return this.View();
        }

        [CustomAuthorize(Roles = RoleConstants.AdminRole)]
        public ActionResult UserPermissions()
        {
            var permissions = new List<UserPermissions>();

            foreach (MembershipUser user in this.MembershipService.GetAllUsers())
            {
                var useTable = this.RoleProvider.IsUserInRole(user.UserName, RoleConstants.TablesUsageRole);
                var useBlobs = this.RoleProvider.IsUserInRole(user.UserName, RoleConstants.BlobsUsageRole);

                permissions.Add(new UserPermissions()
                {
                    User = user.UserName,
                    TablesUsage = useTable,
                    BlobsUsage = useBlobs
                });
            }

            this.ViewData.Model = permissions;

            return this.View();
        }

        [CustomAuthorize(Roles = RoleConstants.AdminRole)]
        public ActionResult TablePermissions()
        {
            var permissions = new List<TablePermissions>();
            var tables = this.CloudTableClient.ListTables();

            foreach (var table in tables)
            {
                if (!table.Equals("secMembership", StringComparison.OrdinalIgnoreCase)
                    && !table.Equals("secRole", StringComparison.OrdinalIgnoreCase))
                {
                    var accessRole = table + RoleConstants.TableRoleSuffix;
                    var publicRole = table + RoleConstants.PublicTableRoleSuffix;
                    var isPublic = this.RoleProvider.RoleExists(publicRole);
                    var users = this.RoleProvider.RoleExists(accessRole) ? this.RoleProvider.GetUsersInRole(accessRole) : new string[0];

                    permissions.Add(new TablePermissions()
                    {
                        Table = table,
                        IsPublic = isPublic,
                        Users = users
                    });
                }
            }

            var usersList = new List<string>();

            foreach (MembershipUser user in this.MembershipService.GetAllUsers())
            {
                usersList.Add(user.UserName);
            }

            this.ViewData["users"] = usersList;
            this.ViewData.Model = permissions;

            return this.View();
        }

        [CustomAuthorize(Roles = RoleConstants.AdminRole)]
        [HttpGet]
        public void SetUserPermissions(string user, bool useTables, bool useBlobs)
        {
            string[] users = { user };

            string[] tableRoles = { RoleConstants.TablesUsageRole };
            string[] blobsRoles = { RoleConstants.BlobsUsageRole };

            if (useTables)
            {
                this.RoleProvider.AddUsersToRoles(users, tableRoles);
            }
            else if (this.RoleProvider.IsUserInRole(user, RoleConstants.TablesUsageRole))
            {
                this.RoleProvider.RemoveUsersFromRoles(users, tableRoles);
            }

            if (useBlobs)
            {
                this.RoleProvider.AddUsersToRoles(users, blobsRoles);
            }
            else if (this.RoleProvider.IsUserInRole(user, RoleConstants.BlobsUsageRole))
            {
                this.RoleProvider.RemoveUsersFromRoles(users, blobsRoles);
            }
        }

        [CustomAuthorize(Roles = RoleConstants.AdminRole)]
        [HttpGet]
        public void AddTablePermission(string table, string user)
        {
            var tableRole = table + RoleConstants.TableRoleSuffix;

            if (!this.RoleProvider.RoleExists(tableRole))
            {
                this.RoleProvider.CreateRole(tableRole);
            }

            string[] users = { user };
            string[] roles = { tableRole };

            this.RoleProvider.AddUsersToRoles(users, roles);
        }

        [CustomAuthorize(Roles = RoleConstants.AdminRole)]
        [HttpGet]
        public void RemoveTablePermission(string table, string user)
        {
            var tableRole = table + RoleConstants.TableRoleSuffix;

            if (this.RoleProvider.RoleExists(tableRole) && this.RoleProvider.IsUserInRole(user, tableRole))
            {
                string[] users = { user };
                string[] roles = { tableRole };
                this.RoleProvider.RemoveUsersFromRoles(users, roles);
            }
        }

        [CustomAuthorize(Roles = RoleConstants.AdminRole)]
        [HttpGet]
        public void SetTablePublic(string table, bool isPublic)
        {
            var tableRole = table + RoleConstants.PublicTableRoleSuffix;

            if (isPublic)
            {
                if (!this.RoleProvider.RoleExists(tableRole))
                {
                    this.RoleProvider.CreateRole(tableRole);
                }
            }
            else
            {
                if (this.RoleProvider.RoleExists(tableRole))
                {
                    this.RoleProvider.DeleteRole(tableRole, true);
                }
            }
        }

        private static CloudStorageAccount GetStorageAccountFromConfigurationSetting()
        {
            CloudStorageAccount account = null;

            try
            {
                account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
            }
            catch (InvalidOperationException)
            {
                account = null;
            }

            return account;
        }
    }
}
